#include "systemc.h"
#include "random.h"
#include "structs.h"
#include "channel.h"

#define INSTR_RS_ADDR instr.range(23,21)
#define INSTR_RT_ADDR instr.range(18,16)
#define INSTR_RD_ADDR instr.range(13,11)

SC_MODULE(decode)
{
//-------------in-out---------------------------------------------------------//
	sc_port< async_channel_in_if< sc_uint<32> > > fede_instruction;
	sc_port< async_channel_out_if< deex > > deex_struct;
	sc_port< async_channel_in_if< sc_int<32> > > dmde_data_out;
	sc_port< async_channel_out_if< sc_int<32> > > dedm_data_in;
	sc_port< async_channel_in_if< sc_int<32> > > exde_rd;
//----------------------------------------------------------------------------//

//-------------Variáveis-Locais-----------------------------------------------//
	deex DeEx;
	sc_uint<32> instr;
//----------------------------------------------------------------------------//

	void behavior()
	{
		sc_int<32> reg[] = {
			0x0000000,
			0x0000001,
			0x0000002,
			0x0000003,
			0x0000004,
			0x0000005,
			0x0000006,
			0x0000007
		};

		while(true)
		{
			fede_instruction->read(instr);

			DeEx.func = instr.range(5,0);
			DeEx.op = instr.range(31,26);
			DeEx.rs = reg[INSTR_RS_ADDR];
			DeEx.rt = reg[INSTR_RT_ADDR];
			DeEx.rd = reg[INSTR_RD_ADDR];
			DeEx.offset = instr.range(15,0);

			deex_struct->write(DeEx);

			switch(DeEx.op)
			{
				case 0x0: //ALU op
					exde_rd->read(reg[INSTR_RD_ADDR]); //reg[rd]
					break;

				case 0x4: //beq
					break;

				case 0x23: //lw
					dmde_data_out->read(reg[INSTR_RT_ADDR]); //reg[rt]
					break;

				case 0x2b: //sw
					dedm_data_in->write(reg[INSTR_RT_ADDR]); //reg[rt]
					break;
					
				case 0x08: //addi
					exde_rd->read(reg[INSTR_RT_ADDR]);
					break;

				default:
					cout << "error:decode: invalid opcode (0x" << hex << DeEx.op << ")" << endl;
					break;
			}
		}
	}

	SC_CTOR(decode)
	{
		SC_THREAD(behavior);
	}
};